//
//  SLPullDownRefreshControl.swift
//  0319iOSweiboDemo
//
//  Created by Tang on 16/3/28.
//  Copyright © 2016年 大天朝. All rights reserved.
//

import UIKit
//MARK: - 扩展UIScolleView.动态添加下拉刷新
private var pullDownRefreshingControlKey = "pullDownRefreshingControlKey"
extension UIScrollView {
    //使用运行时.动态关联对象.
   private var pullDownRefreshingControl: SLPullDownRefreshControl {
        get {
            //在对象身上根据key来去对象
            if let refreshControl = objc_getAssociatedObject(self, &pullDownRefreshingControlKey) as? SLPullDownRefreshControl {
                return refreshControl
            } else {
                //在对象身上没找到需要的东西
                let refreshControl = SLPullDownRefreshControl()
                
                //添加到scrollview上面
                self.addSubview(refreshControl)
                
                //将refreshControl关联
                self.pullDownRefreshingControl = refreshControl
                return refreshControl
            }
        }
        set {
            //将newValue添加到self上
            objc_setAssociatedObject(self, &pullDownRefreshingControlKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    //MARK: - 添加2个方法
    func addPullDownRefreshingControlHandle(handle: () -> ()) {
        pullDownRefreshingControl.pulldownRefreshHandler = handle
    }
    
    ///开始刷新
    func startRefreshing() {
        pullDownRefreshingControl.startRefreshing()
    }
    
    ///结束刷新
    func endRefreshing() {
        pullDownRefreshingControl.endRefresh()
    }
    
}

//刷新控件的3中状态
enum pullDownRefreshControlStatus: Int {
    case Normal         ///箭头朝下.下拉刷新
    case PullToRefresh  ///箭头朝上.释放刷新
    case Refreshing     ///正在刷新
}


private let pullDownRefreshControlHeight:CGFloat = 60


class SLPullDownRefreshControl: UIView {
    
    //MARK: - 属性
    //刷新控件开始刷新的回调
    var pulldownRefreshHandler: (() -> ())?
    
    //父类.定义属性的时候属性类型后面是!
    //UIScrollView!: 表示可选类型.  隐式拆包  使用的时候可以不用拆包.需要保证在使用的时候一定有值
    //和?有区别.如果是用UIScrollView?.后面使用需要强制拆包.如果使用UIScrollView!后面使用不需要强制拆包.如果值为nil,也会崩
    private weak var scrollView: UIScrollView!
    
    //记录上一次的状态
    private var oldStatus: pullDownRefreshControlStatus = .Normal
    
        //刷新控件的当前刷新状态.默认是Normal
    private var currentStatus: pullDownRefreshControlStatus = .Normal {
        didSet {
            //状态改变后来改变UI
            switch currentStatus {
            case .Normal:
                //移除菊花的旋转动画
                fhlView.layer.removeAllAnimations()
                arrowView.hidden = false
                fhlView.hidden = true
                //箭头转下来.文字改变.变为:下拉刷新
                messageLabel.text = "下拉刷新"
                UIView.animateWithDuration(SLDefaultDuration, animations: { () -> Void in
                    self.arrowView.transform = CGAffineTransformIdentity
                })

            //只有上次是刷新状态.再切换到Normal让tableview往上走刷新控件的高度.把刷新控件隐藏掉
               if oldStatus == .Refreshing {
                    UIView.animateWithDuration(SLDefaultDuration, animations: { () -> Void in
                        self.scrollView.contentInset.top -= pullDownRefreshControlHeight
                        
                    })
                }

            case .PullToRefresh:
                //箭头旋转.文字改变.变为:释放刷新
                messageLabel.text = "释放刷新"
                UIView.animateWithDuration(SLDefaultDuration, animations: { () -> Void in
                    self.arrowView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))
                 })
            case .Refreshing:
                //箭头隐藏.文字改变.变为:正在刷新
                arrowView.hidden = true
                fhlView.hidden = false
                messageLabel.text = "正在刷新..."
                let rotation = CABasicAnimation(keyPath: "transform.rotation")
                rotation.toValue = M_PI * 2
                rotation.duration = 0.5
                rotation.repeatCount = MAXFLOAT
                //forKey:nil动画叠加了  forKey != nil 重新动画
                fhlView.layer.addAnimation(rotation, forKey: "rotation")
                
                //修改scrollView.contentInset.top的值.让tableview不要移动到原来的位置.需要下移动刷新控件的高度.就能显示刷新控件
                UIView.animateWithDuration(SLDefaultDuration, animations: { () -> Void in
                    
                    self.scrollView.contentInset.top += pullDownRefreshControlHeight
                    
                    }, completion: { (_) -> Void in
                        //刷新控件到导航栏下方的时候调用
                        self.pulldownRefreshHandler?()
                })
            }
            //需要在didSet最下面来赋值之前的状态
            oldStatus = currentStatus
        }
       
    }
    
    //MARK: - 公开方法
    ///开始刷新
    func startRefreshing() {
        currentStatus = .Refreshing
    }
    ///结束刷新.别人加载到数据后来调用
    func endRefresh() {
        currentStatus = .Normal
    }
    
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    //移除KVO
    deinit {
        scrollView.removeObserver(self, forKeyPath: "contentOffset")
    }
    
   override init(frame: CGRect) {
    let newFrame = CGRect(x: 0, y: -pullDownRefreshControlHeight, width: UIScreen.width, height: pullDownRefreshControlHeight)
    
        super.init(frame: newFrame)
    
        prepareUI()
    }

    
    func prepareUI() {
        backgroundColor = UIColor.clearColor()
        //添加子控件
        addSubview(arrowView)
        addSubview(fhlView)
        addSubview(messageLabel)
        
        //添加约束
        arrowView.translatesAutoresizingMaskIntoConstraints = false
        fhlView.translatesAutoresizingMaskIntoConstraints = false
        messageLabel.translatesAutoresizingMaskIntoConstraints = false
        
        //隐藏菊花
        fhlView.hidden = true
        //箭头
        addConstraint(NSLayoutConstraint(item: arrowView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: -30))
        addConstraint(NSLayoutConstraint(item: arrowView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
        
        //菊花
        addConstraint(NSLayoutConstraint(item: fhlView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0))
        addConstraint(NSLayoutConstraint(item: fhlView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
        
        //文字
        addConstraint(NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 8))
        addConstraint(NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
    }
    
    //view即将被添加到父控件上面.当调用addSubview后触发
    //newSuperview: 父类
    override func willMoveToSuperview(newSuperview: UIView?) {
        super.willMoveToSuperview(newSuperview)
        
        
        //KVO. 监听对象属性的改变tableView.contentOffest
        if let scrollView = newSuperview as? UIScrollView {
            self.scrollView = scrollView
            
            /**
            *  scrollView. 监听的对象
            *  observer: NSObject : 谁来监听
            *  forKeyPath : 监听的属性
            *  options : New.  Old
            *  context : 上下文
            */
            scrollView.addObserver(self, forKeyPath: "contentOffset", options: [NSKeyValueObservingOptions.New , NSKeyValueObservingOptions.Old], context: nil)

        }
    }
    /**
        Normal <-> PullToRefresh 判断:contentOffset.y = -64 - 60 = -124 还需要判断当前的状态
            1.Normal: contentOffest.y > -124        -120
            2.PullToRefresh: contentOffest. < -124   130
     -64 = -scrollView.contentInset.top
     -60 = -pullDownRefreshControlHeight
     */

    
     
    //当监听对象的属性发生改变时回调
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
//        SLPrint(msg: "scrollView.contentOffset: \(scrollView.contentOffset)")
        if scrollView.dragging {
//            SLPrint(msg: "keyPath: \(keyPath), change: \(change)")
            //scrollView正在处于手指拖动
            //手指拖动tableView  Normal <-> PullToRefresh之间的状态切换
            if currentStatus == .PullToRefresh && scrollView.contentOffset.y > -scrollView.contentInset.top - pullDownRefreshControlHeight {
//                SLPrint(msg: "切换到Normal")
                currentStatus = .Normal
            } else if currentStatus == .Normal && scrollView.contentOffset.y < -scrollView.contentInset.top - pullDownRefreshControlHeight {
//                SLPrint(msg: "切换到PullToRefresh")
                currentStatus = .PullToRefresh
            }
        } else if currentStatus == .PullToRefresh {//手指松开
            //当松手的时候.如果是PullToRefresh状态就切换到Refreshing
//            SLPrint(msg: "切换到Refreshing")
            currentStatus = .Refreshing
        }
    }
    //MARK: - 懒加载
    //箭头
    private lazy var arrowView: UIImageView = UIImageView(image: UIImage(named: "tableview_pull_refresh"))
    
    //菊花
    private lazy var fhlView: UIImageView = UIImageView(image: UIImage(named: "tableview_loading"))
    
    //文字
    private lazy var messageLabel: UILabel = {
       let label = UILabel()
        label.textColor = UIColor.darkGrayColor()
        label.text = "下拉刷新"
        label.font = UIFont.systemFontOfSize(SLStatusCellContentSize)
        return label
    }()
}
